from typing import Optional
from fastapi import APIRouter, HTTPException, status, Depends
from pydantic import BaseModel, Field
from datetime import date
from database import get_db

router = APIRouter(
    prefix="/cards",
    tags=["cards"],
)


class CardBase(BaseModel):
    cardID: str
    customerID: int
    savingID: int
    openMoney: float
    balance: float
    curID: Optional[str] = "RMB"
    openDate: Optional[date] = None
    IsReportLoss: Optional[bool] = False


class CardCreate(CardBase):
    password: Optional[str] = Field(default="888888", alias="pass")


class CardUpdate(BaseModel):
    savingID: Optional[int] = None
    curID: Optional[str] = None
    balance: Optional[float] = None
    password: Optional[str] = None
    IsReportLoss: Optional[bool] = None


class ChangePasswordRequest(BaseModel):
    old_password: str
    new_password: str


class ChangeReportLossStatusRequest(BaseModel):
    password: str
    new_status: bool


@router.post("/", status_code=status.HTTP_201_CREATED)
def add_bank_card(card: CardCreate, conn=Depends(get_db)):
    try:
        cursor = conn.cursor()
        args = (
            card.cardID,
            card.customerID,
            card.savingID,
            card.curID,
            card.openDate,
            card.openMoney,
            card.balance,
            card.password,
            card.IsReportLoss,
        )
        cursor.callproc("sp_AddBankCard", args)
        conn.commit()
        return {"message": "Bank card added successfully."}
    except Exception as e:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
    finally:
        cursor.close()


@router.post("/{card_id}/change-password", status_code=status.HTTP_200_OK)
def change_card_password(card_id: str, request: ChangePasswordRequest, conn=Depends(get_db)):
    cursor = conn.cursor()
    try:
        args = [card_id, request.old_password, request.new_password, 0, ""]
        result_args = cursor.callproc("sp_ChangeCardPassword", args)
        conn.commit()

        result_code = result_args[3]
        result_message = result_args[4]

        if result_code == 0:
            return {"message": result_message}
        else:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST, detail=result_message
            )

    except Exception as e:
        conn.rollback()
        if isinstance(e, HTTPException):
            raise e
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e)
        )
    finally:
        cursor.close()


@router.post("/{card_id}/report-loss", status_code=status.HTTP_200_OK)
def change_report_loss_status(
    card_id: str, request: ChangeReportLossStatusRequest, conn=Depends(get_db)
):
    cursor = conn.cursor()
    try:
        args = [card_id, request.password, request.new_status, 0, ""]
        result_args = cursor.callproc("sp_ChangeReportLossStatus", args)
        conn.commit()

        result_code = result_args[3]
        result_message = result_args[4]

        if result_code == 0:
            return {"message": result_message}
        else:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST, detail=result_message
            )

    except Exception as e:
        conn.rollback()
        if isinstance(e, HTTPException):
            raise e
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e)
        )
    finally:
        cursor.close()


@router.delete("/{card_id}", status_code=status.HTTP_204_NO_CONTENT)
def delete_bank_card(card_id: str, conn=Depends(get_db)):
    try:
        cursor = conn.cursor()
        cursor.callproc("sp_DeleteBankCard", (card_id,))
        conn.commit()
    except Exception as e:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
    finally:
        cursor.close()


@router.put("/{card_id}")
def update_bank_card(card_id: str, card: CardUpdate, conn=Depends(get_db)):
    try:
        cursor = conn.cursor()
        args = (
            card_id,
            card.savingID,
            card.curID,
            card.balance,
            card.password,
            card.IsReportLoss,
        )
        cursor.callproc("sp_UpdateBankCard", args)
        conn.commit()
        return {"message": "Bank card updated successfully."}
    except Exception as e:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
    finally:
        cursor.close()


@router.get("/{card_id}")
def get_bank_card_by_id(card_id: str, conn=Depends(get_db)):
    try:
        cursor = conn.cursor(dictionary=True)
        cursor.callproc("sp_GetBankCardById", (card_id,))
        for result in cursor.stored_results():
            card_info = result.fetchone()
        if card_info:
            return card_info
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND, detail="Card not found"
        )
    finally:
        cursor.close()


@router.get("/by_customer/{customer_id}")
def get_bank_cards_by_customer_id(customer_id: int, conn=Depends(get_db)):
    try:
        cursor = conn.cursor(dictionary=True)
        cursor.callproc("sp_GetBankCardsByCustomerId", (customer_id,))
        cards = []
        for result in cursor.stored_results():
            cards = result.fetchall()
        return cards
    finally:
        cursor.close()


@router.get("/")
def get_all_bank_cards(conn=Depends(get_db)):
    try:
        cursor = conn.cursor(dictionary=True)
        cursor.callproc("sp_GetAllBankCards")
        for result in cursor.stored_results():
            cards = result.fetchall()
        return cards
    finally:
        cursor.close()
